/*
  一、initMap 返回的是一个 promise 对象, 结果就是这个地图是否加载完毕
  二、使用 根html加入
    <script type="text/javascript">
      window._AMapSecurityConfig = {
        securityJsCode: "d17ed2af881b0dc5669139c5b92199cf", // 密钥
      };
    </script>
    <script src="https://webapi.amap.com/maps?v=2.0&key=419ec683dad39455a40ba92cb8cd64c9&plugin=AMap.DistrictLayer"></script>
*/
import axios from "axios";
class Bus {
  constructor() {
    this.allEvent = Object.create(null)
  }

  // 发布
  on(eventType, handler) {
    this.allEvent[eventType] = this.allEvent[eventType] || []
    this.allEvent[eventType].push(handler)
  }

  // 订阅
  emit(eventType, ...args) {
    if(this.allEvent[eventType]){
      this.allEvent[eventType].forEach(handler => {
        handler(...args)
      })
    }
  }

  // 取消订阅
  off(eventType) {
    if(this.allEvent[eventType]) this.allEvent[eventType] = []
  }

  // 全部取消
  close(){
    this.allEvent = Object.create(null)
  }
}

// 地图类
class Mp extends Bus {
  constructor() {
    super()
    // 默认值
    this.initMapParams = {
      el: "Mmp", // 必传 地图容器的id
      areaName: "北京", // 默认定位北京
      center: [116.405285, 39.904989], // 定位的中心点坐标
      satellite: true, // 卫星图
      roadNet: true, // 路网
      icon: "https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png", // 点位图片
      iconSize: [21, 31], // 点位图片大小
      overTemplate: () => `<div class="amap-info-window"> ${ '我是参数, 我可以接受一个形参, 即: overData里面的data对象' } <div class="amap-info-sharp" style="width: 0;height: 0;border: 8px solid transparent;position: absolute;left: 50%;transform: translateX(-50%);border-top-color: rgba(18, 75, 109, 0.8);"></div></div>`, // 鼠标滑过的函数模板,返回一个html结构的字符串即可
      overData: [], // 鼠标滑过的点位信息包含数据,坐标等(坐标必须要有 [lng,lat] ) e.g  overData: [{ center: [lng, lat], data:{ name: '点位展示的内容', inner: '点位滑过的内容', iconData: { url:'点位地址', showText: false } } }] iconData.showText--->是否展示文字默认false
      iconOffset: [1, 18], // 点位的偏移量
      iconPcolor: "#fff", // 点位里面文字的颜色
      iconPsize: 10, // 点位里面文字的大小
      click: false, // 是否支持点位 "点击" 事件
      hover: false, // 是否支持点位 "滑过" 事件
      css: '' // 指定css样式（css字符串, css写法, 不能scss嵌套）
    };
    this.district = null;
    this.polygon = null;
    this.map = null;
    this.css = `
    .amap-info-window {
      white-space:nowrap;
      font-size: 14px;
      padding: 3px 7px;
      border: 1px solid #61c7e6;
      box-shadow: 0 0 10px 1px #61c7e6 !important;
      background: rgba(18, 75, 109, 0.8);
      border-radius: 5px;
      position: relative;
      color: #fff;
    }
    .amap-info-content {
      box-shadow: 0 0 10px 3px #61c7e6 !important;
      background: rgba(18, 75, 109, 0.8);
      border-radius: 5px;
      color: #fff;
      font-size: 12px;
      padding: 10px;
      border: none;
    }
    .map-inner-wrap {
      padding: 10px;
    }
    .amap-info-close {
      color: #fff;
    }
    .amap-info-sharp {
      border-top-color: rgba(18, 75, 109, 0.8) !important;
    }
    ` // 默认css样式
  }

  // 初始化参数
  initP(params = {}) {
    for (let key in this.initMapParams) {
      (params[key] || params[key] == false) ? (this.initMapParams[key] = params[key]) : ''
    }
  }

  // 设置地图弹出框的样式
  setCss(css) {
    let style = document.createElement('style')
    let logo = document.createElement('style') // 去掉logo
    let head = document.getElementsByTagName('head')[0]
    style.type = 'text/css'
    logo.innerHTML = `
    .amap-logo {
      display: none !important;
    }
    .amap-copyright {
      opacity: 0;
    }
    `
    if(css.length !== 0){
      style.innerText = this.initMapParams.css
    }else{
      style.innerText = this.css
    }
    head.appendChild(logo)
    head.appendChild(style)
  }

  // 是否引入密钥
  secret() {
    if(!window._AMapSecurityConfig || !window._AMapSecurityConfig.securityJsCode) alert('您没有设置密钥！可能会影响地图的功能!')
  }

  // 初始化地图
  initMap(params) {
    this.secret() // 是否引入密钥
    this.initP(params); // 初始化参数
    this.setCss(this.initMapParams.css) // 设置弹框样式
    this.map?.destroy();
    return new Promise((resolve, reject) => {
      try {
        //初始化地图对象，加载地图
        this.map = new AMap.Map(this.initMapParams.el, {
          center: this.initMapParams.center, //地图中心点
          zoom: 9, //地图显示的缩放级别
          layers: this.whichMap(),
          showLabel: false,
          keyboardEnable: false,
        });
        this.map.on("complete", (e) => {
          this.addMask();
          this.addPoints(resolve);
        });
      } catch (error) {
        if(String(error).includes('AMap is not defined')) alert("您没有引入高德地图api, 并设置key");
        if(String(error).includes('Map container div not exist')) alert('您的容器可能不存在, 或者el没有对应容器id')
      }
    });
  }

  // 加遮罩
  addMask(searchName = this.initMapParams.areaName) {
    // 加载行政区划插件
    // 实例化DistrictSearch
    let opts = {
      subdistrict: 0, //获取边界不需要返回下级行政区
      extensions: "all", //返回行政区边界坐标组等具体信息
      level: "district", //查询行政级别为 市
    };

    // 异步加载插件
    AMap.plugin("AMap.DistrictSearch", () => {
      this.district = this.district ? this.district : new AMap.DistrictSearch(opts);

      this.district.search(searchName, (status, result) => {
        if (this.polygon) {
          this.map.remove(this.polygon); //清除上次结果
          this.polygon = null;
        }
        let bounds = this.equation(this.initMapParams, result.districtList); // 取正确的区域遮罩
        // 遮罩 👇
        let outer = [
          new AMap.LngLat(-360, 90, true),
          new AMap.LngLat(-360, -90, true),
          new AMap.LngLat(360, -90, true),
          new AMap.LngLat(360, 90, true),
        ];
        let pathArray = [outer];
        pathArray.push.apply(pathArray, bounds);
        if (bounds) {
          //生成行政区划polygon
          for (let i = 0; i < bounds.length; i += 1) {
            bounds[i] = [bounds[i]];
          }
          this.polygon = new AMap.Polygon({
            path: bounds,
            strokeWeight: 1, // 边界宽度
            strokeColor: "#34e3e1", // 边界颜色
            fillColor: "black", // 这找颜色
            fillOpacity: 0.7, // 遮罩透明度
          });
          this.polygon.setPath(pathArray);
          this.map.add(this.polygon);
        }
      });
    });
  }

  // 取 传进来的区域 和 遮罩搜索的区域 center相等的值( 因为有些地区名字相同, 会遮罩加载错位 ) ( 相差正负0.5的都算一个地区 )
  equation(areaV, maskV) {
    return maskV.find((i) => (Math.floor(areaV.center[0]) <= Math.floor(i.center.lng) + 0.5 || Math.floor(areaV.center[0]) >= Math.floor(i.center.lng) - 0.5) && (Math.floor(areaV.center[1]) <= Math.floor(i.center.lat) + 0.5 || Math.floor(areaV.center[1]) >= Math.floor(i.center.lat) - 0.5)).boundaries;
  }

  // 什么地图判断
  whichMap() {
    let arr = [];
    if (this.initMapParams.satellite) arr.push(new AMap.TileLayer.Satellite()); // 卫星图
    if (this.initMapParams.roadNet) arr.push(new AMap.TileLayer.RoadNet()); // 路网
    return arr;
  }

  // 加点 ( 海量标注 LabelMarker )
  addPoints(resolve) {
    let layer = new AMap.LabelsLayer({
      zooms: [3, 20],
      zIndex: 1000,
      collision: false,
    });

    // 将图层添加到地图
    this.map.add(layer);
    let markers = [];

    let icon = {
      type: "image",
      image: this.initMapParams.icon,
      size: this.initMapParams.iconSize,
      anchor: "center-center",
      data: "", // 每个点位的具体数据
    };
    console.log('当前数据量为:-->', this.initMapParams.overData.length, '条');
    for (let i in this.initMapParams.overData) {
      let curPosition = this.initMapParams.overData[i].center;
      icon.data = this.initMapParams.overData[i].data; // 设置每个点位数据
      icon.image = this.initMapParams.overData[i].data.iconData.url; // 设置每个点位图片路径
      let curData = {
        position: curPosition,
        icon,
        text: {
          content: this.initMapParams.overData[i].data.iconData.showText ? this.initMapParams.overData[i].data.name.slice(0, 1) : "",
          offset: this.initMapParams.iconOffset,
          style: {
            fontSize: this.initMapParams.iconPsize, // 字体大小
            fillColor: this.initMapParams.iconPcolor,
          },
        },
      };
      let labelMarker = new AMap.LabelMarker(curData);
      markers.push(labelMarker);
      // 点位点击事件
      if(this.initMapParams.click) {
        labelMarker.on("click", (e) => {
          this.openWindow(e.data)
          this.emit('ck', e)
        })
      };
      // 给marker绑定hover事件
      if(this.initMapParams.hover) this.hoverWindow(labelMarker, this.initMapParams.overData[i].data); // 1 maker对象   2每个点位的数据
    }
    // 一次性将海量点添加到图层
    layer.add(markers);
    // 标记点添加完毕回调
    layer.on("complete", (e) => {
      resolve(e);
    });
  }

  // 鼠标滑过点位展示的弹窗
  hoverWindow(labelMarker, data) {
    // 普通点
    let normalMarker = new AMap.Marker({
      anchor: "bottom-center",
      offset: [0, -10],
    });
    labelMarker.on("mouseover", (e) => {
      let position = e.data.data && e.data.data.position;
      if (position) {
        normalMarker.setContent(this.initMapParams.overTemplate(data));
        normalMarker.setPosition(position);
        this.map.add(normalMarker);
      }
    });
    labelMarker.on("mouseout", () => {
      this.map.remove(normalMarker);
    });
  }

  // 点击回调函数
  click(cb) {
    this.close() // 先取消所有订阅, 防止重复订阅bug
    this.on('ck', (data) => {
      cb(data)
    })
  }

  // 点位弹框
  openWindow(data) {
    // 创建 infoWindow 实例
    let infoWindow = new AMap.InfoWindow({
      anchor: "bottom-center", //窗体出现位置
    });
    infoWindow.setContent(data.opts.icon.data.ck_inner)//传入 dom 对象，或者 html 字符串
    // 打开信息窗体
    infoWindow.open(this.map, data.data.position);
  }

  // 获取实时天气
  getWeather(name = '北京'){
    return new Promise((resolve, reject) => {
      //加载天气查询插件
      AMap.plugin('AMap.Weather', () => {
      //创建天气查询实例
      let weather = new AMap.Weather();
      //执行实时天气信息查询
      weather.getLive(name, (err, data) => {
          if(!err){
            resolve(data)
          }else{
            reject(err)
          }
        });
      });
    })
  }
}

export default new Mp();
